<?php
class Form {
    protected $tpl;
	
    protected $formName;
    protected $formShowReset;
    protected $formSubmitValue;
    protected $fileFieldExists = false;
    protected $useIPLock = false;
    protected $allowPreview = false;
    protected $useCaptcha = false;

	protected $ipLockLength = 60;

    protected $fields = array();
    
    
    public static $TYPE_SELECT = "select";
    public static $TYPE_TEXT = "text";
    public static $TYPE_CHECKBOX = "checkbox";
    public static $TYPE_TEXTAREA = "textarea";
    public static $TYPE_RADIO = "radio";
    public static $TYPE_FILE = "file";
    public static $TYPE_PASSWORD = "password";
    public static $TYPE_HIDDEN = "hidden";
    
    public static $CHECK_TEXT_NOTEMPTY = "notEmpty";
    public static $CHECK_TEXT_NUMERIC = "numeric";
    public static $CHECK_TEXT_EMAIL = "email";
    public static $CHECK_TEXT_HOMEPAGE = "homepage";
    
    public static $CHECK_TEXTAREA_NOTEMPTY = "notEmpty";
    
    public function __construct() {
       $this->tpl = General::getTpl();
    }
    
    public function initByData($formName,$formShowReset,$formSubmitValue,$fields,$useIPLock = false,$allowPreview = false,$useCaptcha = false) {
       $this->formName = $formName;
       $this->formShowReset = $formShowReset;
       $this->formSubmitValue = $formSubmitValue;
       $this->useIPLock = $useIPLock;
	   $this->allowPreview = $allowPreview;
	   $this->useCaptcha = $useCaptcha;
	
		$this->ipLockLength = Settings::getInstance()->getSetting("general.ipLockLength");
	
       $this->fields = $fields;
       
       $this->prepareFields();
    }
    
    public function deleteSpecialChars($text) {
        $output = str_replace(array('ä','ü','ö','ß','%',' ','(',')','&','"',"'","<",">"),
                              array('ae','ue','ou','ss','','_','_','_','_','','','','')
                            ,$text);
        return $output; 
    }
    
    protected function htmlspecialcharsArray($input) {
        if (is_array($input)) {
          foreach ($input AS $key => $value) {
             if (!is_array($value)) {
                $value = htmlspecialchars($value);
                //$key = addslashes($key);
                $output[$key] = $value;
             }else{
               $output[$key] = $this->htmlspecialcharsArray($value);
             }
          }
       }else{
       	$output = htmlspecialchars($input);
       }
       return $output;
    }
    
    
    // INSERT LOGIN-STUFF
    protected function prepareFields() {
    	foreach($this->fields as $key => $f) {
    		if(!isset($this->fields[$key]['formName']))
    			$this->fields[$key]['formName'] = $this->deleteSpecialChars($f['fieldName']);
    			
            if($f['fieldType'] == Form::$TYPE_SELECT) {
                $this->fields[$key]['fieldDefaultValue'] = $this->htmlspecialcharsArray($f['fieldDefaultValue']);
                $this->fields[$key]['selectOptions'] = explode("::--::",htmlspecialchars($f['fieldSelectOptions']));
                $this->fields[$key]['selectOptionsSpecial'] = explode("::--::",htmlspecialchars($f['fieldSelectOptions']));
                if(isset($this->fields[$key]['fieldSelectKey'])) {
                	$this->fields[$key]['fieldSelectKey'] = explode("::--::",htmlspecialchars($f['fieldSelectKey']));
                }else{
                	$this->fields[$key]['fieldSelectKey'] = $this->fields[$key]['selectOptionsSpecial'];
                }
                if(!isset($this->fields[$key]['fieldDisplayBBCodeSmilies'])) {
                	$this->fields[$key]['fieldDisplayBBCodeSmilies'] = false;
                }
            }
            
            if($f['fieldType'] == Form::$TYPE_TEXTAREA) {
                $rowsCols = explode("_",$f['fieldSelectOptions']);
                $this->fields[$key]['cols'] = $rowsCols[0];
                $this->fields[$key]['rows'] = $rowsCols[1];
            }
            
            if($f['fieldType'] == Form::$TYPE_RADIO) {
                $this->fields[$key]['fieldDefaultValue'] = htmlspecialchars($f['fieldDefaultValue']);
                $this->fields[$key]['radioValues'] = explode(",",htmlspecialchars($f['fieldRadioValues']));
                $this->fields[$key]['radioValuesSpecial'] = explode(",",htmlspecialchars($f['fieldRadioValues']));
            }
            
            // Existiert ein File-Feld? (wegen enctype)
            if($f['fieldType'] == Form::$TYPE_FILE) $this->fileFieldExists = true;
            
            // Login
            if(isset($f['loginRequired']) && $f['loginRequired'] == true) unset($this->fields[$key]);
    	}
    }
    
    public function outputFormular($varName,$tplFile) {
    	$this->tpl->assign('formName',$this->formName);
    	$this->tpl->assign('formShowReset',$this->formShowReset);
    	$this->tpl->assign('formSubmitValue',$this->formSubmitValue);
		/* PREVIEW? */
    	$this->tpl->assign('formAllowPreview',$this->allowPreview);
		/* CAPTCHA? */
    	$this->tpl->assign('formUseCaptcha',$this->useCaptcha);
		if($this->useCaptcha == true) {
			$captcha = new Captcha;
	        $code = $captcha->genCode();
	        General::getTpl()->assign('captchaCode',md5($code));
			$captcha->createImg('160','40',$code,"./kernel/captcha/");
		}

    	
    	// CSRF-Protection
		General::getTpl()->assign('md5FormName',md5($this->formName));
		$sessionId = General::genHash(4);
		$this->tpl->assign('formSessionId',$sessionId);
    	$hash = sha1(md5(time()).md5(General::genHash(30)));
    	$_SESSION[$sessionId."_hash"] = $hash;
    	$this->tpl->assign('hash',$hash);
    	
    	$formvalue = array();
    	
    	foreach($this->fields as $f) {
    		if(isset($f['fieldDisplayBBCodeSmilies']) && $f['fieldDisplayBBCodeSmilies'] == true) {
                require_once './kernel/smilies.php';
                Smilies::outputSmilies('smilieForm');
    		}
    		$formvalue[$f['formName']] = $this->htmlspecialcharsArray($f['fieldDefaultValue']);
    	}
    	
    	// Get Old Form-Values
    	foreach($_POST as $key=>$value) {
            if(is_array($value)) {
                $formvalue[$key] = $this->htmlspecialcharsArray($value);
            }else{
                $formvalue[$key] = htmlspecialchars($value);
            }
        }
  
        $this->tpl->assign('fileFieldExists',$this->fileFieldExists);
        $this->tpl->assign('formvalue',$formvalue);
        if(isset($this->fields)) $this->tpl->assign('fields',$this->fields);
    	
    	$this->tpl->assign($varName,
    		$this->tpl->fetch($tplFile));
    }
    
    
    
    public function checkTextField($f,$value) {
        $return = array("fieldName" => $f['fieldName'],
                        "fieldValue" => DB::parseVar($value));
                            
        if($f['fieldCheck'] == false) {
            return $return;
        }else{
            // Kontrollen
            $error = "";
            if($f['fieldCheckExtra'] == Form::$CHECK_TEXT_NOTEMPTY && empty($value)) 
                $error = "Das Feld \"".$f['fieldName']."\" muss ausgef&uuml;llt werden.";
            if($f['fieldCheckExtra'] == Form::$CHECK_TEXT_NUMERIC && !is_numeric($value)) 
                $error = "Das Feld \"".$f['fieldName']."\" muss eine Zahl sein.";
            if($f['fieldCheckExtra'] == Form::$CHECK_TEXT_EMAIL && ($this->checkEmail($value) == false)) 
                $error = "Das Feld \"".$f['fieldName']."\" muss eine Email-Adresse sein.";
            if($f['fieldCheckExtra'] == Form::$CHECK_TEXT_HOMEPAGE && ($this->checkHomepage($value) == false) ) 
                $error = "Das Feld \"".$f['fieldName']."\" muss eine Homepage-Adresse sein.";

            if(empty($error)) {
                return $return;
            }else{
                $return = array("fieldName" => $f['fieldName'],
                                "fieldError" => $error);
                return $return;
            }
        }
    }
    
    public function checkSelectField($f,$value) {
        // Gibt keine Kontrollen
        
        // Value
        if(!is_array($value)) {
            $returnVal = DB::parseVar($value);
        }else{
            $returnVal = implode(",",$value);
            $returnVal = DB::parseVar($returnVal);
        }
        $return = array("fieldName" => $f['fieldName'],
                        "fieldValue" => $returnVal);
        return $return;
    }
    
    public function checkCheckField($f,$value) {
        // Gibt keine Kontrollen
        
        // Value
        if($value == "ok") {
            $returnVal = "checked";
        }else{
            $returnVal = "/";
        }
        $return = array("fieldName" => $f['fieldName'],
                        "fieldValue" => $returnVal);
        return $return;
    }
    
    public function checkTextareaField($f,$value) {
        $return = array("fieldName" => $f['fieldName'],
                        "fieldValue" => DB::parseVar(nl2br($value)));
                            
        if($f['fieldCheck'] == false) {
            return $return;
        }else{
            // Kontrollen
            $error = "";
            if($f['fieldCheckExtra'] == Form::$CHECK_TEXTAREA_NOTEMPTY && empty($value)) 
                $error = "Das Feld \"".$f['fieldName']."\" muss ausgef&uuml;llt werden.";
            
            if(empty($error)) {
                return $return;
            }else{
                $return = array("fieldName" => $f['fieldName'],
                                "fieldError" => $error);
                return $return;
            }
        }
    }
    
    
    public function checkRadioField($f,$value) {
        // Gibt keine Kontrollen
        
        // Value
        
        $return = array("fieldName" => $f['fieldName'],
                        "fieldValue" => DB::parseVar($value));
        return $return;
    }
    
    public function checkFileField($f,$value) {
        if(empty($value['name'])) {
            // Keine Datei
            $return = array("fieldName" => $f['fieldName'],
                            "fieldValue" => "Keine Datei");
            return $return;
        }
        
        $return = array("fieldName" => $f['fieldName'],
                        "fieldValue" => $value['name'],
                        "fieldUpload" => $value);
                            
        if($f['fieldCheck'] == false) {
            return $return;
        }else{
            // Kontrollen
            $error = "";
            // Dateityp
            if( $f['fieldCheckExtra'] == 'fileType' || $f['fieldCheckExtra'] == "both" ) {
                // Endung der hochgeladenen Datei
                $extension = pathinfo($value['name']);
                $ext = $extension['extension'];
                // Erlaubte Endungen
                $allowedExt = explode(",",$f['fieldFileMimeTypes']);
                // Kontrolle
                if(!in_array($ext,$allowedExt)) 
                    $error = "Die ausgew&auml;hlte Datei hat einen nicht erlaubten Dateityp.<br /> Erlaubte Dateitypen: ".$f['fieldFileMimeTypes'];
            }
            
            // Dateigroesse
            if( $f['fieldCheckExtra'] == 'fileSize' || $f['fieldCheckExtra'] == "both" ) {
                // Dateigroesse in kB
                $fileSizeKB = $value['size'] / 1024;
                // Kontrolle
                if($fileSizeKB > $f['fieldFileMaxSize']) 
                    $error = "Die ausgew&auml;hlte Datei ist zu gro&szlig;. Die Datei darf maximal ".$f['fieldFileMaxSize']."kByte gro&szlig; sein.";
            }
            
            if(empty($error)) {
                return $return;
            }else{
                $return = array("fieldName" => $f['fieldName'],
                                "fieldError" => $error);
                return $return;
            }
        }
    }

	public function isPreview() {
		if($this->allowPreview == true && isset($_POST['preview'])) {
			return true;
		}
		return false;
	}
    
    public function completeCheck() {
	    if(isset($_POST['submit']) || ($this->allowPreview == true && isset($_POST['preview']))) {
			// Check Form => Insert contains name/value or error
		    $insert = $this->checkForm();
		    
		    // Fehler?
		    $errors = "";
		    foreach($insert as $returnArray) {
		        if(isset($returnArray['fieldError'])) {
		            $errors .= '<li>'.$returnArray['fieldError'].'</li>';
		            $highlightError[$returnArray['fieldName']] = true;
		        }
		    }
		    
		    if($this->useIPLock == true) {
		    	require_once './kernel/IPLock.php';
		    	if(IPLock::stillLocked("form_".$this->formName,General::getIP(),$this->ipLockLength)) {
		    		$errors = "<li>Sie k&ouml;nnen nicht so schnell hintereinander das Formular abschicken. Sie k&ouml;nnen nur alle ".$this->ipLockLength." Sekunden das Formular abschicken";
		    	}
		    }
		    
		    if(empty($errors)) {
		    	// PReview?
				if($this->isPreview()) {
					return 'preview';
				}
				
		    	// ADD IP-Lock
		    	if($this->useIPLock == true) {
		    		require_once './kernel/IPLock.php';
		    		IPLock::insertIpSperre("form_".$this->formName,General::getIP());
		    	}
		        return true;
		    }else{
		        // Fehler:
		        General::getTpl()->assign('errorMsg',General::getTpl()->get_template_vars('errorMsg').$errors);
		        if(is_array(General::getTpl()->get_template_vars('highlightError'))) {
		        	$highlightError = array_merge($highlightError,General::getTpl()->get_template_vars('highlightError'));
		        }
		        if(isset($highlightError)) General::getTpl()->assign('highlightError',$highlightError);
		        return false;
		    }
		}
		return false;
    }
    
    public function addError($errorMsg,$highlightFieldName) {
    	// Fehler:
		General::getTpl()->assign('errorMsg',General::getTpl()->get_template_vars('errorMsg').$errorMsg);
		
		$highlightError[$highlightFieldName] = true;
		if(is_array(General::getTpl()->get_template_vars('highlightError'))) {
			$highlightError = array_merge($highlightError,General::getTpl()->get_template_vars('highlightError'));
		}
		General::getTpl()->assign('highlightError',$highlightError);
    }
    
    
    /**
     * Checks the Form and returns an array with the name/value or the error
     * message
     */
    public function checkForm() {
    	if(!isset($_SESSION[$_POST[md5($this->formName).'_formSessionId']."_hash"]) || 
			$_SESSION[$_POST[md5($this->formName).'_formSessionId']."_hash"] != $_POST[md5($this->formName).'_hash']) {
			//echo $_SESSION[$this->formName."_".$_POST['formSessionId']."_hash"]."  ".$_POST[$this->formName.'_hash'];
    		die("HackOr");
    	}
    	$insert = array();
    	foreach($this->getFields() as $f) {
	        if($f['fieldType'] == "text" || $f['fieldType'] == "password" || $f['fieldType'] == "hidden") {
	            $insert[] = $this->checkTextField($f,$_POST[$f['formName']]);
	        }elseif($f['fieldType'] == "select") {
	            if(!isset($_POST[$f['formName']])) $_POST[$f['formName']] = "";
	            $insert[] = $this->checkSelectField($f,$_POST[$f['formName']]);
	        }elseif($f['fieldType'] == "checkbox") {
	            if(!isset($_POST[$f['formName']])) $_POST[$f['formName']] = "";
	            $insert[] = $this->checkCheckField($f,$_POST[$f['formName']]);
	        }elseif($f['fieldType'] == "textarea") {
	            $insert[] = $this->checkTextareaField($f,$_POST[$f['formName']]);
	        }elseif($f['fieldType'] == "radio") {
	            $insert[] = $this->checkRadioField($f,$_POST[$f['formName']]);
	        }elseif($f['fieldType'] == "file") {
	            $insert[] = $this->checkFileField($f,$_FILES[$f['formName']]);
	        }
    	}

		if($this->useCaptcha == true) {
			// Check Captcha
			if(md5($_POST['checkCaptcha']) != $_POST['captchaCode'] ) {
				$insert[] = array("fieldName" => "captcha",
	                               "fieldError" => "Sie haben einen falschen Captcha-Code angegeben.");
			}
		}
			
    	return $insert;
    }
    
	public function checkEmail($email) {
        $email = eregi("^[a-z0-9]+([-_\.]?[a-z0-9])+@[a-z0-9]+([-_\.]?[a-z0-9])+\.[a-z]{2,4}", $email);
        if($email == false) return false;
        else return true;
    }
    
    private function checkHomepage($homepage) {
        if(filter_var($homepage, FILTER_VALIDATE_URL) === FALSE) return false;
        else return true;
    }
    
    public function getFields() {
    	return $this->fields;
    }

	public function setIPLength($length) {
		$ipLockLength = $length;
	}
}
?>